#include <iostream>
using namespace std;
#include "meta/type_list.h"
#include "meta/tlc_gen.h"
using namespace tdl;

template <typename T>
class holder
{
public:
	T value;
	
	holder() {}
	holder(const T& v) : value(v) {}
	operator T&() { return value; }
	operator const T&() const { return value; }
	friend inline ostream& operator<<(ostream& os, const holder& h)
	{
		os << h.value;
		return os;
	}
};

typedef tuple<make_type_list<int, int, string>::type> rtype;
rtype foo()
{
	return rtype(7, -13, string("hello"));
}

/////////////////////
int main(int argc, char *argv[])
{
	// test for gen_scatter
	cout << "===== test for gen_scatter =====" << endl;
	typedef make_type_list<char, short, int, long>::type mytl;
	typedef tlc::gen_scatter<mytl, holder> cache_types;
	cache_types caches_obj;
	
	holder<char>& ch = tlc::get_obj<char>(caches_obj);
	ch.value = 'c';
	cout << "char=" << tlc::get_obj<char>(caches_obj) << endl;

	int& i = tlc::get_obj<2>(caches_obj);
	tlc::get_obj<2>(caches_obj) = 321;
	cout << "char=" << i << endl;
	
	cout << "sizeof(cache_types)=" << sizeof(caches_obj) << endl;

	// test for gen_linear
	cout << "===== test for gen_linear =====" << endl;
	typedef make_type_list<char, int, int>::type mytl2;
	typedef tlc::gen_linear<mytl2, tuple_unit> holders_type;
	holders_type holders;

	enum { iii = 1 };
	tlc::get_obj<0>(holders) = 'b';
	tlc::get_obj<1>(holders) = 0;
	tlc::get_obj<2>(holders) = 1;
	for(int i = 1; i < 5; i++)
	{
		tlc::get_obj<iii>(holders) += i;
		tlc::get_obj<iii + 1>(holders) *= i;

		cout << "tlc::get_obj<0>(holders)=" << tlc::get_obj<0>(holders) << endl;
		cout << "tlc::get_obj<1>(holders)=" << tlc::get_obj<1>(holders) << endl;
		cout << "tlc::get_obj<2>(holders)=" << tlc::get_obj<2>(holders) << endl;
		cout << "tlc::get_obj<int>(holders)=" << tlc::get_obj<int>(holders) << endl;
		cout << "sizeof(holders_type)=" << sizeof(holders) << endl;
	}

	// test for tuple
	cout << "===== test for tuple=====" << endl;
	rtype r = foo();
	cout << "filed<0>=" << tlc::get_obj<0>(r.objs) << endl;
	cout << "field<1>=" << tlc::get_obj<1>(r.objs) << endl;
	cout << "field<2>=" << tlc::get_obj<2>(r.objs) << endl;

	return 0;
}

